function tif_table = tiftable(file_name);

% TIFTABLE - read multi-image TIF header information
%
%    TABLE = TIFTABLE(FNAME) reads all image file directories in the 
%    TIFF file specified by the FNAME.
%
%    NOTE:  this is NOT a TIFF 6.0 compliant reader for a number of
%           reasons - I try to point these reasons out along the way!
%
%           If a TIFF 6.0 compliant reader is required, use IMFINFO
%           and IMREAD instead.

% By:   S.C. Molitor (smolitor@med.unc.edu)
% Date: April 21, 2000

% default parameters

endian_fmt = 'ieee-le';		% use little endian format for FOPEN()

% default structures

header_field = {'endian', 'identifier', 'offset'};
header_type = {'char 2', 'uint16', 'uint32'};
header_size = 8;

entry_field = {'tag', 'type', 'count', 'offset'};
entry_type = {'uint16', 'uint16', 'uint32', 'uint32'};
entry_size = 12;

% identifiers strings/values

LITTLE_ENDIAN = 'II';	% TIFF values are little endian
BIG_ENDIAN = 'MM';		% TIFF values are big endian
TIFF_IDENT = 42;			% TIFF file identifier

% initialize output

tif_table = [];

% validate arguments

if (nargin ~= 1)
   msgbox('Invalid number of arguments', 'TIFTABLE Error', 'warn');
   return
elseif (~ischar(file_name) | isempty(file_name))
   msgbox('FNAME must be a character string', 'TIFTABLE Error', 'warn');
   return
end

% open file
% set pointer to BOF

fid = fopen(file_name, 'rb', endian_fmt);
if (fid == -1)
   msgbox(sprintf('Cannot open %s', file_name), 'TIFTABLE Error', 'warn');
   return
end
status = fseek(fid, 0, 'bof');
if (status ~= 0)
   msgbox(sprintf('Cannot find BOF in %s', file_name), 'TIFTABLE Error', 'warn');
   fclose(fid);
   return
end

% read file header

[A, count] = fread(fid, header_size, 'uint8');
if (count == header_size)
   header_struct = n2struct(uint8(A), header_field, header_type);
else
   msgbox(sprintf('Cannot read header of %s', file_name), 'TIFTABLE Error', 'warn');
   fclose(fid);
   return
end

% determine if file has correct format
% cannot read big-endian files because of N2STRUCT routine
% obtain offset to first image file directory (IFD)

if (~strcmp(header_struct.endian, LITTLE_ENDIAN))
   msgbox(sprintf('%s is not little-endian (%s)', file_name, header_struct.endian), 'TIFTABLE Error', 'warn');
   fclose(fid);
   return
elseif (header_struct.identifier ~= TIFF_IDENT)
   msgbox(sprintf('%s has invalid identifier (%d)', file_name, header_struct.identifier), 'TIFTABLE Error', 'warn');
   fclose(fid);
   return
else
   offset = header_struct.offset;
end

% read IFD entries
% exit loop if EOF or error

while (1)
   
   % set file pointer to specified location
   
   status = fseek(fid, offset, 'bof');
   if (status ~= 0)
      msgbox(sprintf('Cannot find IFD %d in %s (%08X)', entry_count, file_name, offset), 'TIFTABLE Error', 'warn');
      break
   end
   
   % read number of entries in IFD
   
   [num_entry, count] = fread(fid, 1, 'uint16');
   if (count ~= 1)
      msgbox(sprintf('Cannot read number of IFD entries in %s (%08X)', file_name, offset), 'TIFTABLE Error', 'warn');
      break
   end
   
   % loop through entries in selected IFD
   
   for i = 1 : num_entry
      
      % read selected entry
      
      [A, count] = fread(fid, entry_size, 'uint8');
      if (count == entry_size)
         entry_struct = n2struct(uint8(A), entry_field, entry_type);
      else
         msgbox(sprintf('Cannot read header %d/%d in %s (%08X)', ...
            i, num_entry, file_name, offset), 'TIFTABLE Error', 'warn');
         break
      end
      
      % add entry to output
      
      if (isempty(tif_table))
         tif_table = entry_struct;
      else
         tif_table(end + 1) = entry_struct;
      end
   end
   
   % find offset of next IFD
   % exit if offset is zero
   
   [A, count] = fread(fid, 1, 'uint32');
   if (count == 1)
      if (A == 0)
         break
      else
         offset = A;
      end
   else
      msgbox(sprintf('Cannot read offset of next IFD in %s (%08X)', file_name, offset), 'TIFTABLE Error', 'warn');
      break
   end
   
end

% close file and exit

fclose(fid);
return

